package com.fintech.common.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;

public class ShaUtil {
	 /**
     * 对字符串加密,加密算法使用MD5,SHA-1,SHA-256,默认使用SHA-256
     *
     * @param strSrc
     *            要加密的字符串
     * @param encName
     *            加密类型
     * @return
     */
    public static String Encrypt(String strSrc, String encName) {
        MessageDigest md = null;
        String strDes = null;

        byte[] bt = strSrc.getBytes();
        try {
            if (StringUtils.isEmpty(encName)) {
                encName = "SHA-256";
            }
            md = MessageDigest.getInstance(encName);
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        return strDes;
    }

    private static String bytes2Hex(byte[] bts) {
        String des = "";
        String tmp = null;
        for (int i = 0; i < bts.length; i++) {
            tmp = (Integer.toHexString(bts[i] & 0xFF));
            if (tmp.length() == 1) {
                des += "0";
            }
            des += tmp;
        }
        return des;
    }
   /**
    * 供融云使用
    * @param value
    * @return
    */
    public static String hexSHA1(String value) {
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			md.update(value.getBytes("utf-8"));
			byte[] digest = md.digest();
			return byteToHexString(digest);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	
	private static String byteToHexString(byte[] bytes) {
		return String.valueOf(Hex.encodeHex(bytes));
	}
	

	/**
	 * SHA256数据加密
	 * 
	 * @param content
	 * @return
	 */
	public static String encrypt(String content) throws Exception {
		return encrypt(content, true);
	}
	
	public static String encrypt(String content, boolean isBase64) throws Exception {
		MessageDigest messageDigest;
		try {
			messageDigest = MessageDigest.getInstance("SHA-256");
			messageDigest.update(content.getBytes("UTF-8"));
			if (isBase64) {
				return Base64.encodeBase64String(messageDigest.digest()); // to base64
			}
			return bytes2Hex(messageDigest.digest()); // to HexString
		} catch (Exception e) {
			throw new Exception("SHA256加密出现异常", e);
		}
	}

	/**
	 * 通过SHA进行签名处理<BR>
	 * 1.按MAP的KEY进行顺序排序<BR>
	 * 2.格式为channelCode=xx&param1=xx&param2=xx&key=xx<BR>
	 * 
	 * @param map
	 *            业务参数MAP
	 * @param channelCode
	 *            渠道编号
	 * @param key
	 *            摘要KEY
	 * @return
	 * @throws Exception
	 */
	public static String signWithSHA(Map<String, String> map, String channelCode, String key) throws Exception {
		String content = dealParam(map, channelCode, key);
		return encrypt(content);
	}
	
	public static String signWithSHA(Map<String, String> map, String channelCode, String key, String mobileNo) throws Exception {
		String content = dealParam(map, channelCode, key, mobileNo);
		return encrypt(content);
	}
	
	private static String dealParam(Map<String, String> map, String channelCode, String key) throws Exception {
		StringBuilder sb = new StringBuilder();
		// 对参数MAP进行排序
		List<Entry<String, String>> sortMap = mapSort(map);
		sb.append("fjChnlCode=").append(channelCode).append("&");
		for (int i = 0; i < sortMap.size(); i++) {
			sb.append(sortMap.get(i).getKey()).append("=").append(sortMap.get(i).getValue()).append("&");
		}
		sb.append("key=").append(key);
		return sb.toString();
	}
	
	private static String dealParam(Map<String, String> map, String channelCode, String key, String mobileNo) throws Exception {
		StringBuilder sb = new StringBuilder();
		// 对参数MAP进行排序
		List<Entry<String, String>> sortMap = mapSort(map);
		sb.append("fjChnlCode=").append(channelCode).append("&");
		for (int i = 0; i < sortMap.size(); i++) {
			sb.append(sortMap.get(i).getKey()).append("=").append(sortMap.get(i).getValue()).append("&");
		}
		sb.append("key=").append(key);
		return sb.toString();
	}
	
	/**
	 * SHA验签
	 * 
	 * @param map
	 *            业务参数MAP
	 * @param channelCode
	 *            渠道编号
	 * @param key
	 *            摘要KEY
	 * @param sign
	 *            签名值
	 * @return
	 * @throws Exception
	 */
	public static boolean validateSignWithSHA(Map<String, String> map, String channelCode, String key, String sign)
			throws Exception {
		if (StringUtils.isEmpty(sign)) {
			return false;
		}
		String content = dealParam(map, channelCode, key);
		if (!sign.equals(encrypt(content))) {
			return sign.equals(encrypt(content, false));
		}
		return true;
	}
	
	/**
	 * SHA验签
	 * 
	 * @param map
	 *            业务参数MAP
	 * @param channelCode
	 *            渠道编号
	 * @param key
	 *            摘要KEY
	 * @param sign
	 *            签名值
	 * @param mobileNo
	 * 			  手机号
	 * @return
	 * @throws Exception
	 */
	public static boolean validateSignWithSHA(Map<String, String> map, String channelCode, String key, String mobileNo, String sign)
			throws Exception {
		if (StringUtils.isEmpty(sign)) {
			return false;
		}
		String content = dealParam(map, channelCode, key, mobileNo);
		if (!sign.equals(encrypt(content))) {
			return sign.equals(encrypt(content, false));
		}
		return true;
	}
	
	/**
	 * 对MAP进行升级排序，按KEY来
	 * 
	 * @param map
	 * @return
	 */
	public static List<Map.Entry<String, String>> mapSort(Map<String, String> map) {
		List<Map.Entry<String, String>> list = new ArrayList<Entry<String, String>>(map.entrySet());
		// 然后通过比较器来实现排序
		Collections.sort(list, new Comparator<Entry<String, String>>() {
			// 升序排序
			public int compare(Entry<String, String> o1, Entry<String, String> o2) {
				return o1.getKey().compareTo(o2.getKey());
			}
		});
		return list;
	}
	/**
	 * utf编码sha-256加密
	 * @param strSrc
	 * @param encName
	 * @return
	 */
	public static String EncryptUTF(String strSrc, String encName) {
        MessageDigest md = null;
        String strDes = null;
        try {
        	byte[] bt = strSrc.getBytes("utf-8");
            if (StringUtils.isEmpty(encName)) {
                encName = "SHA-256";
            }
            md = MessageDigest.getInstance(encName);
            md.update(bt);
            strDes = bytes2Hex(md.digest()); // to HexString
        } catch (Exception e) {
        	e.printStackTrace();
            return null;
        }
        return strDes;
    }
	public static void main(String[] args) throws Exception {
		Map<String, String> map = new HashMap<String, String>();
		// map.put("timestamp", System.currentTimeMillis() + "");
		map.put("channelCode", "Q5188LUICv3T");
		map.put("codeType", "2");
		map.put("width", "400");
		map.put("height", "400");
		map.put("codeContent", "1");
		map.put("mobileNo", "17711607905");
		String sign = signWithSHA(map, "Q5188LUICv3T", "Hy5bEy0mIpei3pxKUGkP", "17711607905");
		System.out.println(sign);
		System.out.println(validateSignWithSHA(map,  "Q5188LUICv3T", "Hy5bEy0mIpei3pxKUGkP", "17711607905", sign));
		
		System.out.println(encrypt("fjChnlCode=xxx&orderNo=xxx&timestamp=xxx&extField=xxx&callUrl=xxx&key=xxx"));
		System.out.println(encrypt("fjChnlCode=xxx&orderNo=xxx&timestamp=xxx&extField=xxx&callUrl=xxx&key=xxx", false));
		System.out.println(encrypt("测试RSA加密加签功能"));
	}
}
